﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace net.xBei.Models.json {
    /// <summary>
    /// 标准的返回结构，用于不关心<see cref="ResponseData.Data"/>的具体类型的场景。
    /// </summary>
    public struct ResponseData {
        /// <summary>
        /// 是否成功
        /// </summary>
        public bool Success { get; set; }
        /// <summary>
        /// 错误信息
        /// </summary>
        public string? Message { get; set; }
        /// <summary>
        /// 返回数据
        /// </summary>
        public object? Data { get; set; }
        /// <summary>
        /// 代码
        /// </summary>
        public int Code { get; set; }

        /// <summary>
        /// 是否空
        /// </summary>
        [JsonIgnore]
        public readonly bool IsEmpty => !Success && Code == default && Data == default && Message == default;
        /// <summary>
        /// 输出错误
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="data"></param>
        /// <param name="code"></param>
        /// <returns></returns>
        public static ResponseData Error(string msg, object? data = null, int code = -1) {
            return new ResponseData {
                Message = msg,
                Data = data,
                Code = code,
            };
        }
        /// <summary>
        /// 参数错误
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="paramName"></param>
        /// <param name="rawValue"></param>
        /// <param name="errorMessage"></param>
        /// <returns></returns>
        public static ResponseData BadRequest<T>(string paramName, T rawValue, string errorMessage) {
            return new ResponseData<object> {
                Success = false,
                Code = 400,
                Message = "输入参数错误",
                Data = new[]{ new {
                    param = paramName,
                    rawValue ,
                    errorMessage
                } }
            };
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TT"></typeparam>
        /// <param name="msg"></param>
        /// <param name="data"></param>
        /// <param name="code"></param>
        /// <returns></returns>
        public static ResponseData<TT> Error<TT>(string msg, TT data, int code = -1) {
            return new ResponseData<TT> {
                Data = data,
                Message = msg,
                Code = code,
            };
        }
        /// <summary>
        /// 成功
        /// </summary>
        /// <returns></returns>
        public static ResponseData Ok(object? data = null) {
            return new ResponseData {
                Success = true,
                Data = data,
            };
        }
        /// <summary>
        /// 成功
        /// </summary>
        /// <typeparam name="TT"></typeparam>
        /// <param name="data"></param>
        /// <returns></returns>
        public static ResponseData<TT> Ok<TT>(TT data) {
            return new ResponseData<TT> {
                Success = true,
                Data = data,
            };
        }
        /// <summary>
        /// 直接返回一个 资源不存在
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <returns></returns>
        public static ResponseData<TResult> NotFound<TResult>() {
            return new ResponseData<TResult> {
                Success = false,
                Code = 404,
                Message = "Not Found",
            };
        }
        /// <summary>
        /// 批量操作的返回
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="resultList"></param>
        /// <returns></returns>
        public static ResponseData<Batch<T>> BatchResult<T>(IEnumerable<ResponseData<T>> resultList) {
            if (resultList.All(d => !d.Success)) {
                return new ResponseData<Batch<T>> {
                    Success = false,
                    Data = Batch<T>.Fail(resultList),
                    Message = "全部失败",
                    Code = 90001,
                };
            }
            return new ResponseData<Batch<T>> {
                Success = true,
                Data = Batch<T>.Create(resultList),
            };
        }
        /// <summary>
        /// 未实现
        /// </summary>
        /// <returns></returns>
        public static ResponseData NotImplemented() {
            return Error("未实现", code: 500);
        }
        /// <summary>
        /// 未实现
        /// </summary>
        /// <returns></returns>
        public static Task<ResponseData> NotImplementedAsync() {
            return Task.FromResult(Error("未实现", code: 500));
        }
        /// <summary>
        /// 批量处理
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        public struct Batch<TResult> {
            /// <summary>
            /// 成功的处理结果
            /// </summary>
            public IEnumerable<TResult?>? Success { get; set; }
            /// <summary>
            /// 失败的处理结果
            /// </summary>
            public IEnumerable<BatchItem>? Fails { get; set; }
            /// <summary>
            /// 是否空
            /// </summary>
            [JsonIgnore]
            public readonly bool IsEmpty => Success == default && Fails == default;
            /// <summary>
            /// 
            /// </summary>
            public struct BatchItem {
                /// <summary>
                /// 
                /// </summary>
                public string? Message { get; set; }
                /// <summary>
                /// 
                /// </summary>
                public int Code { get; set; }
                //public BatchItem() { }
                internal BatchItem(string? msg, int code) {
                    Message = msg;
                    Code = code;
                }
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="resultList"></param>
            /// <returns></returns>
            public static Batch<TResult> Create(IEnumerable<ResponseData<TResult>> resultList) {
                return new Batch<TResult> {
                    Fails = resultList.Where(i => i.Success == false).Select(i => new BatchItem(i.Message, i.Code)),
                    Success = resultList.Where(i => i.Success).Select(i => i.Data),
                };
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="resultList"></param>
            /// <returns></returns>
            public static Batch<TResult> Fail(IEnumerable<ResponseData<TResult>> resultList) {
                return new Batch<TResult> {
                    Fails = resultList.Select(i => new BatchItem(i.Message, i.Code)),
                };
            }
        }
    }
    /// <summary>
    /// 标准的返回结构，用于关心<see cref="ResponseData{T}.Data"/>的具体类型的场景。
    /// </summary>
    /// <typeparam name="T">指定的返回数据类型</typeparam>
    public struct ResponseData<T> {
        /// <summary>
        /// 是否成功
        /// </summary>
        public bool Success { get; set; }
        /// <summary>
        /// 错误信息
        /// </summary>
        public string? Message { get; set; }
        /// <summary>
        /// 返回T类型数据
        /// </summary>
        public T? Data { get; set; }
        /// <summary>
        /// 代码
        /// </summary>
        public int Code { get; set; }
        /// <summary>
        /// 是否空
        /// </summary>
        [JsonIgnore]
        public readonly bool IsEmpty => !Success && Code == default && Data == null && Message == default;
        /// <summary>
        /// 输出错误
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="code"></param>
        /// <returns></returns>
        public static ResponseData<T> Error(string? msg, int code = -1) {
            return new ResponseData<T> {
                Message = msg,
                Code = code,
            };
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="data"></param>
        /// <param name="code"></param>
        /// <returns></returns>
        public static ResponseData<T> Error(string? msg, T data, int code = -1) {
            return new ResponseData<T> {
                Data = data,
                Message = msg,
                Code = code,
            };
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="result"></param>
        /// <param name="code"></param>
        /// <returns></returns>
        public static ResponseData<T> Error(ResponseData result, int code = -1) {
            return new ResponseData<T> {
                Message = result.Message,
                Code = code,
            };
        }
        /// <summary>
        /// 成功
        /// </summary>
        /// <returns></returns>
        public static ResponseData<T> Ok(T data) {
            return new ResponseData<T> {
                Success = true,
                Data = data,
            };
        }
        /// <summary>
        /// “链式”调用。
        /// 如果<see cref="Success"/>==<see langword="false"/>，则直接返回。
        /// 发生异常会直接抛出。
        /// </summary>
        /// <typeparam name="Tout"></typeparam>
        /// <param name="action"></param>
        /// <param name="errorMsg">默认的错误信息</param>
        /// <returns></returns>
        public readonly ResponseData<Tout> Pipe<Tout>(Func<T?, ResponseData<Tout>> action, string errorMsg = "") {
            if (Success == false) {
                return ResponseData<Tout>.Error(Message ?? errorMsg);
            }
            var result = action.Invoke(Data);
            return result;
        }
        /// <summary>
        /// “链式”调用。
        /// 首先调用<paramref name="check"/>检查是否成功，如果失败则返回错误信息。
        /// 否则调用<paramref name="action"/>处理数据。
        /// 发生异常会直接抛出。
        /// </summary>
        /// <typeparam name="Tout"></typeparam>
        /// <param name="check"></param>
        /// <param name="action"><paramref name="check"/>成功（返回<see langword="true"/>）以后执行</param>
        /// <param name="errorMsg">默认的错误信息</param>
        /// <returns></returns>
        public readonly ResponseData<Tout> Pipe<Tout>(Func<T?, bool> check, Func<T?, Tout> action, string errorMsg = "") {
            if (Success == false) {
                return ResponseData<Tout>.Error(Message);
            }
            if (check.Invoke(Data) == false) {
                return ResponseData<Tout>.Error(string.IsNullOrWhiteSpace(errorMsg) ? "异常错误" : errorMsg);
            }
            var result = action.Invoke(Data);
            if (result == null) {
                return ResponseData<Tout>.Error(string.IsNullOrWhiteSpace(errorMsg) ? "异常错误" : errorMsg);
            }
            return ResponseData.Ok(result);
        }
        /// <summary>
        /// “链式”调用。
        /// 首先调用<paramref name="check"/>检查是否成功，如果失败则返回错误信息。
        /// 否则调用<paramref name="action"/>处理数据。
        /// 发生异常会直接抛出。
        /// </summary>
        /// <typeparam name="Tout">可以和<typeparamref name="T"/>相同</typeparam>
        /// <param name="check"></param>
        /// <param name="action"><paramref name="check"/>成功（返回<see langword="true"/>）以后执行</param>
        /// <param name="getError">在执行<paramref name="action"/>时失败，返回的是<see langword="null"/>时获取错误信息</param>
        /// <param name="errorMsg">默认的错误信息</param>
        /// <returns></returns>
        public readonly ResponseData<Tout> Pipe<Tout>(Func<T?, bool> check, Func<T?, Tout> action, Func<T?, string> getError, string errorMsg = "") {
            if (Success == false) {
                return ResponseData<Tout>.Error(Message);
            }
            if (check.Invoke(Data) == false) {
                var msg = getError.Invoke(Data);
                return ResponseData<Tout>.Error(string.IsNullOrWhiteSpace(msg) ? errorMsg : msg);
            }
            var result = action.Invoke(Data);
            if (result == null) {
                var msg = getError.Invoke(Data);
                return ResponseData<Tout>.Error(string.IsNullOrWhiteSpace(msg) ? errorMsg : msg);
            }
            return ResponseData.Ok(result);
        }
        /// <summary>
        /// 捕获失败
        /// 使用<paramref name="checkFail"/>检查是否错误
        /// 如果失败会执行<paramref name="action"/>
        /// </summary>
        /// <param name="checkFail">检查是否失败</param>
        /// <param name="action"></param>
        /// <returns></returns>
        public readonly ResponseData<T> Catch(Func<ResponseData<T>, bool> checkFail, Action<ResponseData<T>> action) {
            if (checkFail.Invoke(this) == false) {
                return this;
            }
            action.Invoke(this);
            return this;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="errorMsg"></param>
        /// <returns></returns>
        public readonly ResponseData<T> CheckNull(string errorMsg) {
            if (Success == false) {
                return ResponseData<T>.Error(Message);
            }
            if (Data == null) {
                return ResponseData<T>.Error(errorMsg);
            }
            return this;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="func"></param>
        /// <param name="dv"></param>
        /// <returns></returns>
        public readonly TResult Pipe<TResult>(Func<T, TResult> func, TResult dv)
            => Success && Data != null ? func.Invoke(Data) : dv;
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="func"></param>
        /// <param name="dv"></param>
        /// <returns></returns>
        public readonly TResult IsSuccess<TResult>(Func<T, TResult> func, TResult dv) => Success && Data != null ? func.Invoke(Data) : dv;
        /// <summary>
        /// 比较两个 ResponseData 对象是否相等
        /// </summary>
        /// <param name="left">左侧 ResponseData 对象</param>
        /// <param name="right">右侧 ResponseData 对象</param>
        /// <returns>如果两个对象相等则返回 true，否则返回 false</returns>
        public static bool operator ==(ResponseData<T> left, ResponseData<T> right) => left.Equals(right);

        /// <summary>
        /// 比较两个 ResponseData 对象是否不相等
        /// </summary>
        /// <param name="left">左侧 ResponseData 对象</param>
        /// <param name="right">右侧 ResponseData 对象</param>
        /// <returns>如果两个对象不相等则返回 true，否则返回 false</returns>
        public static bool operator !=(ResponseData<T> left, ResponseData<T> right) => !left.Equals(right);
        #region 隐式转换
        /// <summary>
        /// <see cref="ResponseData"/>转<see cref="ResponseData{T}"/>。
        /// 如果<see cref="ResponseData.Data"/>不是<typeparamref name="T"/> 类型，则返回<see langword="default"/>，数据会丢失！
        /// </summary>
        /// <param name="r"></param>
        public static implicit operator ResponseData<T>(ResponseData r) => new() {
            Success = r.Success,
            Data = r.Data is T dd ? dd : default,
            Code = r.Code,
            Message = r.Message,
        };
        /// <summary>
        /// <see cref="ResponseData{T}"/>转<see cref="ResponseData"/>。
        /// </summary>
        /// <param name="r"></param>
        public static implicit operator ResponseData(ResponseData<T> r) => new() {
            Success = r.Success,
            Data = r.Data,
            Code = r.Code,
            Message = r.Message,
        };
        /// <inheritdoc />
        public override readonly bool Equals([NotNullWhen(true)] object? obj) {
            if (obj is ResponseData<T> r) {
                return r.Success == Success && r.Data?.Equals(Data) == true;
            }
            return false;
        }

        /// <inheritdoc />
        public override readonly int GetHashCode()
            => Success
                    ? Data == null ? true.GetHashCode() : Data.GetHashCode()
                    : Code != 0 ? Code.GetHashCode() : Message?.GetHashCode() ?? 0;
        #endregion
    }

}
